package com.jt.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jt.mapper.UserMapper;
import com.jt.pojo.User;
import com.jt.vo.PageResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * @author 刘昱江
 * 时间 2021/5/11
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public List<User> findAll() {
        return userMapper.selectList(null);
    }

    /**
     * 需求:
     * 1.根据用户名和密码查询数据库
     * 2.将密码进行加密处理 md5加密方式
     * 3.如果用户名和密码正确 返回token
     * 4 UUID: 每次生成的UUID几乎不重复.   重复概率 2^128/1
     * b809cd3e-f4fa-11eb-b396-52152e05da50
     *
     * @param user 作用: 在未来生成API文档时 有效果 一般都是默认的
     * @return
     */
    @Override
    public String login(User user) {
        //1.将密码进行加密的处理
        String password = user.getPassword(); //明文
        //2. 将字符串 转化为字节数组
        byte[] passByte = password.getBytes();
        //   将明文加密
        String md5Pass = DigestUtils.md5DigestAsHex(passByte);
        //3. 根据用户名和密文查询数据库
        //Sql: select * from user where uname="xxx" and ps="xx"
        //根据对象中不为null的属性充当where条件!!!!
        user.setPassword(md5Pass);
        QueryWrapper<User> queryWrapper = new QueryWrapper<>(user);
        //从数据库中获取结果
        //bug 数据库admin123会有特定的数据bug


        User userDB = userMapper.selectOne(queryWrapper);

        //不能理解!! 面向对象的知识 理解不到位!!!
        if (userDB == null) {
            //用户名和密码错误 返回null
            return null;
            //业务流程结束
        }

        //如果程序执行到这一行,则数据用户的输入正确的. 返回token
        String token = UUID.randomUUID().toString()
                .replace("-", "");
        return token;
    }

    /**
     * 需求: 进行分页查询   总数 分页后的结果
     * 知识铺垫:  每页20条
     *      Sql: select * from user limit 起始位置,每页条数
     *      第一页:
     *          select * from user limit 0,20  下标[0-19]
     *      第二页:
     *          select * from user limit 20,20 下标[20-39]
     *      第三页:
     *          select * from user limit 40,20 下标[40-59]
     *      第N页:
     *          select * from user limit (n-1)*rows,rows
     * @param pageResult
     * @return
     *  方法实现:
     *          1.手写Sql
     *           ////根据参数查询动态执行分页查询
     *         //
     *         ////start起始页位置
     *         //int start = (pageResult.getPageNum() - 1) * pageResult.getPageNum();
     *         ////size每页条数
     *         //int size = pageResult.getPageSize();
     *         ////分页结果
     *         //List<User> userList = userMapper.findUserListByPage(start, size);
     *         //
     *         ////获取记录总数 利用java自动拆装箱的规范 total是user表中总数的信息
     *         ////暂时不需要where数据的反馈 querymapper：null获取所有的数据
     *         //long total = userMapper.selectCount(null);
     *         ////返回封装数据实现返回
     *         //return pageResult.setTotal(total).setRows(userList);
     *          2.利用MP方式实现
     */

    /**
     * 2.利用MP方式实现
     * 1.分页查询 List<user>
     * 2.获取记录的总数 封装pageResult对象
     */
    @Override
    public PageResult getUserList(PageResult pageResult) {

        //第一部分实现数据的封装
        //1.页数 2.一页的条数 3.查询条件

        int pageNum = pageResult.getPageNum();
        //获取页码页数
        int PageSize = pageResult.getPageSize();
        //获取条件条数

        //参数1：page 封装对象 分页对象
        //Page(pageNum, PageSize);条数  页数
        //*规范写法
        Page<User> page = new Page(pageNum, PageSize);

        //参数2：分页的查询条件 username模糊查询
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //添加条件构造器
        //用户没有传递query 会拼接like关键字 拼接参数
        //要进行动态拼接 传参拼接like condition:true 拼接where条件
        //false不拼接
        //判断用户传参 如果传参 返回true 返回false

        //StringUtils.hasLength用于判断字符串非空
        boolean flag = StringUtils.hasLength(pageResult.getQuery());

        //like模糊查询username/传3个值flag为空不进行拼接
        //*username根据username查询条件如果有值进行查询 无事为空值不执行
        queryWrapper.like(flag, "username", pageResult.getQuery());


        //调用usermapper 里的selectpage方法
        //1.传进去的是page分页对象
        //2.queryWrapper可能查询的queryWrapper对象
        //规则：page2个参数根据分页 查询返回total/分页后的记录4个参数

        //selectPage API调用规则
        //2*规范
        page = userMapper.selectPage(page, queryWrapper);
        //分页都的结果 第二部分userList是分页后的结果
        //*获得User所有属性
        List<User> userList = page.getRecords();
        //total查到的是数据的总数
        long total = page.getTotal();
        //查询后的结果
        //分页后进行封装
        pageResult.setTotal(total).setRows(userList);
        return pageResult;
    }

    @Override
    public void updateStatus(User user) {
        userMapper.updateById(user);
    }

    /**
     * 新增入库：
     * 密码需要加密处理
     * 应该
     */
    @Override
    public void addUser(User user) {
        //密码加密
        byte[] bytes = user.getPassword().getBytes();
        String md5Pass = DigestUtils.md5DigestAsHex(bytes);
        user.setPassword(md5Pass);
        //添加默认状态
        user.setStatus(true);
        //添加date时间 目的保证时间进行统一
        Date date = new Date();
        //setCreated设置创建
        user.setCreated(date).setUpdated(date);
        //实现入库
        userMapper.insert(user);
    }

    @Override
    public User getUserById(Integer id) {
        //重写获取id userMapper
        return userMapper.selectById(id);
    }

    @Override
    @Transactional
    public void updateUser(User user) {
        userMapper.updateById(user);
    }




    /**
     * 关于Spring中的事务策略说明
     *  0.Spring内部有事务的管理器,默认开启.
     *  1.Spring只负责拦截运行时异常.
     *    异常类型:  1.运行时异常  2.检查异常/编译异常 由程序员自己控制
     *  2.属性1: rollbackFor 可以配置特殊的异常类型.遇到某种异常回滚.
     *    属性2: noRollbackFor 可以配置异常类型 遇到某种异常不回滚.
     * @param id
     */

    @Override
    @Transactional //Spring默认提供的事务控制的注解
    public void deleUserById(Integer id) {
        userMapper.deleteById(id);
    }








}
